﻿/*                       NOTICE
 * 
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-10-C-0001, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * Approved for Public Release: 11-2435
 * © 2011 The MITRE Corporation. All Rights Reserved. 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */



using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using InputManager;
using GestureListenerClient.Services.Delegates;
using GestureListenerClient.Services;
using System.Windows.Forms;

namespace GestureControlOfWindowsForm
{
    class GoogleEarthProfile : ApplicationProfile
    {
        private ControlForm windowsControl;

        private int cursorID = -1;

        private PointF anchor;

        public GoogleEarthProfile(ControlForm windowsControl)
        {
            this.windowsControl = windowsControl;
        }

        public void setListener(GestureClient listener)
        {
            SlideGestureDelegate slideGestureDelegate = new SlideGestureDelegate();
            HoldSlideGestureDelegate holdSlideGestureDelegate = new HoldSlideGestureDelegate();
            ZoomGestureDelegate zoomGestureDelegate = new ZoomGestureDelegate();
            TapGestureDelegate tapGestureDelegate = new TapGestureDelegate();
            HoldGestureDelegate holdGestureDelegate = new HoldGestureDelegate();
            DragGestureDelegate dragGestureDelegate = new DragGestureDelegate();

            FiducialObjectDelegate fiducial = new FiducialObjectDelegate();
            fiducial.OnObjectAdded += new FiducialCallbackDelegate.OnFiducialDelegate(fiducial_OnObjectAdded);
            fiducial.OnObjectRemoved += new FiducialCallbackDelegate.OnFiducialDelegate(fiducial_OnObjectRemoved);

            holdSlideGestureDelegate.OnHoldSlideStart += new GestureCallbackDelegate.OnGestureDelegate(holdSlideGestureDelegate_OnHoldSlideStart);
            holdSlideGestureDelegate.OnHoldSlideChange += new GestureCallbackDelegate.OnGestureDelegate(holdSlideGestureDelegate_OnHoldSlideChange);
            holdSlideGestureDelegate.OnHoldSlideEnd += new GestureCallbackDelegate.OnGestureDelegate(holdSlideGestureDelegate_OnHoldSlideEnd);

            slideGestureDelegate.OnSlideStart += new GestureCallbackDelegate.OnGestureDelegate(slideGestureDelegate_OnSlideStart);
            slideGestureDelegate.OnSlideChange += new GestureCallbackDelegate.OnGestureDelegate(slideGestureDelegate_OnSlideChange);
            slideGestureDelegate.OnSlideEnd += new GestureCallbackDelegate.OnGestureDelegate(slideGestureDelegate_OnSlideEnd);

            tapGestureDelegate.OnTap += new GestureCallbackDelegate.OnGestureDelegate(tapGestureDelegate_OnTap);
            //tapGestureDelegate.OnHold += new 
            tapGestureDelegate.OnDoubleTap += new GestureCallbackDelegate.OnGestureDelegate(tapGestureDelegate_OnDoubleTap);

            holdGestureDelegate.OnHoldGesture += new GestureCallbackDelegate.OnGestureDelegate(tapGestureDelegate_OnHold);

            zoomGestureDelegate.OnZoomStart += new GestureCallbackDelegate.OnGestureDelegate(zoomGestureDelegate_OnZoomStart);
            zoomGestureDelegate.OnZoomChange += new GestureCallbackDelegate.OnGestureDelegate(zoomGestureDelegate_OnZoomChange);
            zoomGestureDelegate.OnZoomEnd += new GestureCallbackDelegate.OnGestureDelegate(zoomGestureDelegate_OnZoomEnd);

            dragGestureDelegate.OnDragStart += new GestureCallbackDelegate.OnGestureDelegate(dragGestureDelegate_OnDragStart);
            dragGestureDelegate.OnDragChange += new GestureCallbackDelegate.OnGestureDelegate(dragGestureDelegate_OnDragChange);
            dragGestureDelegate.OnDragEnd += new GestureCallbackDelegate.OnGestureDelegate(dragGestureDelegate_OnDragEnd);

            listener.registerListener(new ListenerRegistration("Slide Listener", new System.Drawing.RectangleF(-2, -2, 4, 4), slideGestureDelegate));
            listener.registerListener(new ListenerRegistration("HoldSlide Listener", new System.Drawing.RectangleF(-2, -2, 4, 4), holdSlideGestureDelegate));
            listener.registerListener(new ListenerRegistration("Tap Listener", new System.Drawing.RectangleF(-2, -2, 4, 4), tapGestureDelegate));
            listener.registerListener(new ListenerRegistration("Zoom Listener", new System.Drawing.RectangleF(-2, -2, 4, 4), zoomGestureDelegate));
            listener.registerListener(new ListenerRegistration("Drag Listener", new System.Drawing.RectangleF(-2, -2, 4, 4), dragGestureDelegate));
            listener.registerListener(new ListenerRegistration("Hold Listener", new System.Drawing.RectangleF(-2, -2, 4, 4), holdGestureDelegate));
        }

        public void moveMouse(PointF point)
        {
            //point.Y = 1 - point.Y;
            //point.X = 3 - point.X;
            Mouse.Move((int)(windowsControl.offsetX + (point.X * windowsControl.width)),
                (int)(windowsControl.offsetY + (point.Y * windowsControl.height)));
        }

        public void fiducial_OnObjectAdded(object source, FiducialArgs e)
        {
            /*IPHostEntry entry = System.Net.Dns.GetHostEntry(path.DnsSafeHost);
            Uri hostUri = new Uri("http://brooklyn.mitre.org:8080/ISR/" + e.Fiducial.ID);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(path);
            request.Method = "POST";
            String data = "";
            //Encode the data
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] dataArr = encoding.GetBytes(data);
            request.ContentLength = dataArr.Length;
            request.ContentType = "application/x-www-form-urlencoded";
            request.Accept = "text/plain";
            //Write the data to the request's stream
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(dataArr, 0, dataArr.Length);
            dataStream.Flush();

            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream respStream = response.GetResponseStream();

                StreamReader reader = new StreamReader(new BufferedStream(response.GetResponseStream()));
                string respData = reader.ReadToEnd();

                dataStream.Close();
                return respData;
            }
            catch (WebException webEx)
            {
                //Perhaps handle later?
                throw webEx;
            }
             */
        }

        public void fiducial_OnObjectUpdated(object source, FiducialArgs e)
        {

        }

        public void fiducial_OnObjectRemoved(object source, FiducialArgs e)
        {
            /*IPHostEntry entry = System.Net.Dns.GetHostEntry(path.DnsSafeHost);
            Uri hostUri = new Uri("http://brooklyn.mitre.org:8080/ISR/" + e.Fiducial.ID);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(path);
            request.Method = "DELETE";
            String data = "";
            //Encode the data
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] dataArr = encoding.GetBytes(data);
            request.ContentLength = dataArr.Length;
            request.ContentType = "application/x-www-form-urlencoded";
            request.Accept = "text/plain";
            //Write the data to the request's stream
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(dataArr, 0, dataArr.Length);
            dataStream.Flush();

            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream respStream = response.GetResponseStream();

                StreamReader reader = new StreamReader(new BufferedStream(response.GetResponseStream()));
                string respData = reader.ReadToEnd();

                dataStream.Close();
                return respData;
            }
            catch (WebException webEx)
            {
                //Perhaps handle later?
                throw webEx;
            }
             **/
        }

        public void tapGestureDelegate_OnTap(object source, GestureArgs e)
        {
            Keyboard.KeyUp(Keys.ShiftKey);
            moveMouse(e.Gesture.Coords[0]);
            Console.WriteLine("Click");
            Mouse.PressButton(Mouse.MouseKeys.Left, 0);
        }

        public void tapGestureDelegate_OnHold(object source, GestureArgs e)
        {
            Mouse.ButtonUp(Mouse.MouseKeys.Left);
            anchor.X = e.Gesture.Coords[0].X;
            anchor.Y = e.Gesture.Coords[0].Y;
            moveMouse(e.Gesture.Coords[0]);
            Keyboard.KeyDown(Keys.ShiftKey);
            Mouse.ButtonDown(Mouse.MouseKeys.Left);
        }

        public void tapGestureDelegate_OnDoubleTap(object source, GestureArgs e)
        {
            moveMouse(e.Gesture.Coords[0]);
            Keyboard.KeyPress(Keys.ControlKey, 300);
            System.Threading.Thread.Sleep(50);
            Keyboard.KeyPress(Keys.ShiftKey, 200);
            System.Threading.Thread.Sleep(50);
            Keyboard.KeyPress(Keys.P, 100);
        }

        /*
        public void tapGestureDelegate_OnHold(object source, GestureArgs e)
        {
            //hold is going to be a continuos key press based on the bearing from center of the screen...so use the angle
            float screenCenterX = .5f;
            float screenCenterY = .5f;
            float gestureX = e.Gesture.Coords[0].X;
            float gestureY = e.Gesture.Coords[0].Y;

            float deltaX = e.Gesture.Coords[0].X - screenCenterX;
            float deltaY = screenCenterY - e.Gesture.Coords[0].Y;


            //double angleDegrees = (Math.Atan((gestureY - screenCenterY) / (gestureX - screenCenterX)))*(180/Math.PI);
            double angleDegrees = (Math.Atan2(deltaY, deltaX)) * (180 / Math.PI);

            if (angleDegrees >= -20 && angleDegrees < 20)
            {

                Keyboard.KeyDown(rightKey);
            }
            else if (angleDegrees >= 20 && angleDegrees < 70)
            {
                Keyboard.KeyDown(rightKey);
                Keyboard.KeyDown(upKey);
            }
            else if (angleDegrees >= 70 && angleDegrees < 110)
            {

                Keyboard.KeyDown(upKey);
            }
            else if (angleDegrees >= 110 && angleDegrees < 160)
            {
                Keyboard.KeyDown(upKey);
                Keyboard.KeyDown(leftKey);
            }
            else if (angleDegrees >= 160 || angleDegrees <= -160)
            {

                Keyboard.KeyDown(leftKey);
            }
            else if (angleDegrees >= -160 && angleDegrees < -110)
            {
                Keyboard.KeyDown(downKey);
                Keyboard.KeyDown(leftKey);
            }
            else if (angleDegrees >= -110 && angleDegrees < -70)
            {
                Keyboard.KeyDown(downKey);

            }
            else if (angleDegrees >= -70 && angleDegrees < -20)
            {
                Keyboard.KeyDown(downKey);
                Keyboard.KeyDown(rightKey);
            }
        }
        */

        public void zoomGestureDelegate_OnZoomStart(object source, GestureArgs e)
        {
            Mouse.ButtonUp(Mouse.MouseKeys.Left);
            PointF center = e.Gesture.Coords[0];
            moveMouse(center);
            anchor = center;
            Mouse.ButtonDown(Mouse.MouseKeys.Right);
        }

        public void zoomGestureDelegate_OnZoomChange(object source, GestureArgs e)
        {
            float magnitude = e.Gesture.Coords[0].X;
            moveMouse(new PointF(anchor.X, anchor.Y + magnitude * windowsControl.zoomSpeed));
        }

        public void zoomGestureDelegate_OnZoomEnd(object source, GestureArgs e)
        {
            Mouse.ButtonUp(Mouse.MouseKeys.Right);
        }

        public void holdSlideGestureDelegate_OnHoldSlideStart(object source, GestureArgs e)
        {
            Mouse.ButtonUp(Mouse.MouseKeys.Left);
            anchor.X = e.Gesture.Coords[0].X;
            anchor.Y = e.Gesture.Coords[0].Y;
            moveMouse(e.Gesture.Coords[0]);
            Keyboard.KeyDown(Keys.ShiftKey);
            Mouse.ButtonDown(Mouse.MouseKeys.Left);
        }

        public void holdSlideGestureDelegate_OnHoldSlideChange(object source, GestureArgs e)
        {
            float deltaY = e.Gesture.Coords[0].Y;
            float newY = anchor.Y + (windowsControl.isYInverted() ? -deltaY : deltaY);
            moveMouse(new PointF(anchor.X + e.Gesture.Coords[0].X, newY));
        }

        public void holdSlideGestureDelegate_OnHoldSlideEnd(object source, GestureArgs e)
        {
            Keyboard.KeyUp(Keys.ShiftKey);
            Mouse.ButtonUp(Mouse.MouseKeys.Left);
        }

        public void slideGestureDelegate_OnSlideStart(object source, GestureArgs e)
        {
            if (cursorID == -1 && e.Gesture.ID != 0)
                cursorID = e.Gesture.ID;
        }

        public void slideGestureDelegate_OnSlideChange(object source, GestureArgs e)
        {
            if (cursorID == e.Gesture.ID)
                moveMouse(e.Gesture.Coords[0]);
        }

        public void slideGestureDelegate_OnSlideEnd(object source, GestureArgs e)
        {
            if (cursorID == e.Gesture.ID)
                cursorID = -1;
        }

        public void dragGestureDelegate_OnDragStart(object source, GestureArgs e)
        {
            moveMouse(e.Gesture.Coords[0]);
            Mouse.ButtonDown(Mouse.MouseKeys.Left);
        }

        public void dragGestureDelegate_OnDragChange(object source, GestureArgs e)
        {
            moveMouse(e.Gesture.Coords[0]);
        }

        public void dragGestureDelegate_OnDragEnd(object source, GestureArgs e)
        {
            moveMouse(e.Gesture.Coords[0]);
            Mouse.ButtonUp(Mouse.MouseKeys.Left);
        }
        /*
        void slideGestureDelegate_OnSlidingGesture(object source, GestureArgs e)
        {

            lastMoveCapture = e.Gesture.GestureTime;
            movePoints.Add(e.Gesture.Coords[0]);
            if (movePoints.Count > 2)
            {
                PointF start = (PointF)movePoints[movePoints.Count - 2];
                PointF last = (PointF)movePoints[movePoints.Count - 1];

                float deltax = start.X - last.X;
                float deltay = start.Y - last.Y;

                String hMoveDir = "";
                String vMoveDir = "";

                if (deltax < 0)
                {

                    if (doOpposite)
                    {
                        hMoveDir = "left";
                    }
                    else
                    {
                        hMoveDir = "right";
                    }
                }
                else
                {

                    if (doOpposite)
                    {
                        hMoveDir = "right";
                    }
                    else
                    {
                        hMoveDir = "left";
                    }
                }

                if (deltay < 0)
                {
                    //swipe down
                    //Console.WriteLine("swipe down");

                    if (doOpposite)
                    {
                        vMoveDir = "up";
                    }
                    else
                    {
                        vMoveDir = "down";
                    }
                }
                else
                {
                    //swipe down
                    //Console.WriteLine("swipe up");
                    if (doOpposite)
                    {
                        vMoveDir = "down";
                    }
                    else
                    {
                        vMoveDir = "up";
                    }
                }
                if (useShiftWithArrow)
                {
                    if (!waitForCleanup || (waitForCleanup && didCleanUp))
                    {
                        Keyboard.KeyDown(Keys.Shift);
                    }
                }
                if (Math.Abs(deltax) > Math.Abs(deltay))
                {

                    if (hMoveDir == "left")
                    {
                        if (!waitForCleanup || (waitForCleanup && didCleanUp))
                        {
                            Console.WriteLine("Left");
                            Keyboard.KeyDown(leftKey);
                            if (useSingleStrike)
                            {
                                Keyboard.KeyUp(leftKey);
                            }
                            didCleanUp = false;

                        }

                    }
                    else
                    {
                        if (!waitForCleanup || (waitForCleanup && didCleanUp))
                        {
                            Console.WriteLine("Right");
                            Keyboard.KeyDown(rightKey);
                            if (useSingleStrike)
                            {
                                Keyboard.KeyUp(rightKey);
                            }
                            didCleanUp = false;


                        }
                    }
                }
                else
                {
                    if (vMoveDir == "up")
                    {
                        if (!waitForCleanup || (waitForCleanup && didCleanUp))
                        {
                            Console.WriteLine("Up");
                            Keyboard.KeyDown(upKey);
                            if (useSingleStrike)
                            {
                                Keyboard.KeyUp(upKey);
                            }
                            didCleanUp = false;

                        }
                    }
                    else
                    {
                        if (!waitForCleanup || (waitForCleanup && didCleanUp))
                        {
                            Console.WriteLine("Down");
                            Keyboard.KeyDown(downKey);
                            if (useSingleStrike)
                            {
                                Keyboard.KeyDown(downKey);
                            }
                            didCleanUp = false;


                        }
                    }
                }
            }
        }

        void pullGestureDelegate_OnPullingGesture(object source, GestureArgs e)
        {
            if (!waitForCleanup || (waitForCleanup && didCleanUp))
            {
                Console.WriteLine("Zoom");
                Keyboard.KeyDown(zoomKey);
                if (useSingleStrike)
                {
                    Keyboard.KeyDown(zoomKey);
                }
                didCleanUp = false;
            }
        }
        */
    }
}
